#include "dspSimulator/targetMachine/dspInstruction.h"
#include "dspSimulator/targetMachine/dspInstInfo.h"

u32 *DspInstruction::src1LoRegPtr = nullptr;
u32 *DspInstruction::src1HiRegPtr = nullptr;
u32 *DspInstruction::src2LoRegPtr = nullptr;
u32 *DspInstruction::src2HiRegPtr = nullptr;
u32 *DspInstruction::dstLoRegPtr = nullptr;
u32 *DspInstruction::dstHiRegPtr = nullptr;
u32 *DspInstruction::cRegPtr = nullptr;
u32 *DspInstruction::cstPtr = nullptr;
u32 *DspInstruction::auxCstPtr = nullptr;

bool DspInstruction::existStandardCondition(std::bitset<32> data) {
    std::bitset<4> creg_z = (data >> 28).to_ulong();
    switch (creg_z.to_ulong()) {
        case 0b0000:
        case 0b1110:
        case 0b1111:
        case 0b0010:
        case 0b0011:
        case 0b0100:
        case 0b0101:
        case 0b0110:
        case 0b0111:
        case 0b1000:
        case 0b1001:
        case 0b1010:
        case 0b1011:
        case 0b1100:
        case 0b1101:
            return true;
        default:
            return false;
    }
}

std::string DspInstruction::getStandardConditionString() const {
    switch (creg_z.to_ulong()) {
        case 0b0000:
        case 0b0001:
        case 0b1110:
        case 0b1111:
            return "";
        case 0b0010:
            return "[B0]";
        case 0b0011:
            return "[!B0]";
        case 0b0100:
            return "[B1]";
        case 0b0101:
            return "[!B1]";
        case 0b0110:
            return "[B2]";
        case 0b0111:
            return "[!B2]";
        case 0b1000:
            return "[A1]";
        case 0b1001:
            return "[!A1]";
        case 0b1010:
            return "[A2]";
        case 0b1011:
            return "[!A2]";
        case 0b1100:
            return "[A0]";
        case 0b1101:
            return "[!A0]";
        default:
            return "";
    }
}

std::string DspInstruction::getSrc1Reg32Name() const {
    std::string regName;
    if (s == 0)
        regName += "A";
    else
        regName += "B";
    regName += std::to_string(src1);
    return regName;
}

std::string DspInstruction::getSrc1Reg64Name() const {
    std::string regName;
    std::string regSide;
    if (s == 0)
        regSide = "A";
    else
        regSide = "B";
    regName = regSide + std::to_string(src1 + 1) + ":" + regSide + std::to_string(src1);
    return regName;
}

std::string DspInstruction::getSrc2Reg32Name() const {
    std::string regName;
    if ((s == 0 && x == 0) || (s == 1 && x == 1))
        regName += "A";
    else
        regName += "B";
    regName += std::to_string(src2);
    return regName;
}

std::string DspInstruction::getSrc2Reg64Name() const {
    std::string regName;
    std::string regSide;
    if ((s == 0 && x == 0) || (s == 1 && x == 1))
        regSide = "A";
    else
        regSide = "B";
    regName = regSide + std::to_string(src2 + 1) + ":" + regSide + std::to_string(src2);
    return regName;
}

std::string DspInstruction::getDstReg32Name() const {
    std::string regName;
    // s位为0时，dst表示A寄存器，s位为1时，dst表示B寄存器
    if (s == 0)
        regName += "A";
    else
        regName += "B";
    regName += std::to_string(dst);
    return regName;
}

std::string DspInstruction::getDstReg64Name() const {
    std::string regName;
    std::string regSide;
    if (s == 0)
        regSide = "A";
    else
        regSide = "B";
    regName = regSide + std::to_string(dst + 1) + ":" + regSide + std::to_string(dst);
    return regName;
}

CRegKind DspInstruction::getCRegKindByCrHiAndCrLo() const {
    if (crhi == 0 && crlo == 0) {
        return control_register::AMR;
    } else if (crhi == 0 && crlo == 1) {
        return control_register::CSR;
    } else if (crhi == 0 && crlo == 0b10001) {
        return control_register::DNUM;
    } else if (crhi == 0 && crlo == 0b11101) {
        return control_register::ECR;
    } else if (crhi == 0 && crlo == 0b11101) {
        return control_register::EFR;
    } else if (crhi == 0 && crlo == 0b10010) {
        return control_register::FADCR;
    } else if (crhi == 0 && crlo == 0b10011) {
        return control_register::FAUCR;
    } else if (crhi == 0 && crlo == 0b10100) {
        return control_register::FMCR;
    } else if (crlo == 0b11000) {
        return control_register::GFPGFR;
    } else if (crhi == 0 && crlo == 0b10110) {
        return control_register::GPLYA;
    } else if (crhi == 0 && crlo == 0b10111) {
        return control_register::GPLYB;
    } else if (crhi == 0 && crlo == 0b00011) {
        return control_register::ICR;
    } else if (crhi == 0 && crlo == 0b00100) {
        return control_register::IER;
    } else if (crhi == 0 && crlo == 0b11111) {
        return control_register::IERR;
    } else if (crhi == 0 && crlo == 0b00010) {
        return control_register::IFR;
    } else if (crhi == 0 && crlo == 0b01101) {
        return control_register::ILC;
    } else if (crhi == 0 && crlo == 0b00110) {
        return control_register::IRP;
    } else if (crhi == 0 && crlo == 0b00010) {
        return control_register::ISR;
    } else if (crhi == 0 && crlo == 0b00101) {
        return control_register::ISTP;
    } else if (crhi == 0 && crlo == 0b11011) {
        return control_register::NRP;
    } else if (crhi == 0 && crlo == 0b11100) {
        return control_register::NTSR;
    } else if (crhi == 0 && crlo == 0b10000) {
        return control_register::PCE1;
    } else if (crhi == 0 && crlo == 0b01111) {
        return control_register::REP;
    } else if (crhi == 0 && crlo == 0b01110) {
        return control_register::RILC;
    } else if (crhi == 0 && crlo == 0b10101) {
        return control_register::SSR;
    } else if (crhi == 0 && crlo == 0b01011) {
        return control_register::TSCH;
    } else if (crhi == 0 && crlo == 0b01010) {
        return control_register::TSCL;
    } else if (crhi == 0 && crlo == 0b11010) {
        return control_register::TSR;
    } else
        return control_register::UNKNOWN_CREG;
}

std::string DspInstruction::getBaseRRegName() const {
    std::string regName;
    // y位为0时，BaseR表示A寄存器，y位为1时，BaseR表示B寄存器
    if (y == 0)
        regName += "A";
    else
        regName += "B";
    regName += std::to_string(baseR);
    return regName;
}

std::string DspInstruction::getOffsetRRegName() const {
    std::string regName;
    // y位为0时，offsetR表示A寄存器，y位为1时，offsetR表示B寄存器
    if (y == 0)
        regName += "A";
    else
        regName += "B";
    regName += std::to_string(offsetR);
    return regName;
}

void DspInstruction::updateRegAndCstPtr(std::shared_ptr<RegisterMap> read, std::shared_ptr<RegisterMap> write) {
    // 如果指令的s位为0，使src1和dst寄存器指针指向regA寄存器
    if (s == 0) {
        dstLoRegPtr = write->getReg32ByName(RegAName[dst])->getDataPtr();
        if (dst != static_cast<u32>(RegAKind::NUM_OF_Reg_A) - 1)
            dstHiRegPtr = write->getReg32ByName(RegAName[dst + 1])->getDataPtr();

        src1LoRegPtr = read->getReg32ByName(RegAName[src1])->getDataPtr();
        if (src1 != static_cast<u32>(RegAKind::NUM_OF_Reg_A) - 1)
            src1HiRegPtr = read->getReg32ByName(RegAName[src1 + 1])->getDataPtr();
    } else {
        // 如果指令的s位为1，使src1和dst寄存器指针指向regB寄存器
        dstLoRegPtr = write->getReg32ByName(RegBName[dst])->getDataPtr();
        if (dst != static_cast<u32>(RegBKind::NUM_OF_Reg_B) - 1)
            dstHiRegPtr = write->getReg32ByName(RegBName[dst + 1])->getDataPtr();

        src1LoRegPtr = read->getReg32ByName(RegBName[src1])->getDataPtr();
        if (src1 != static_cast<u32>(RegBKind::NUM_OF_Reg_B) - 1)
            src1HiRegPtr = read->getReg32ByName(RegBName[src1 + 1])->getDataPtr();
    }

    if ((s == 0 && x == 0) || (s == 1 && x == 1)) {
        // 如果指令的s位为0且x位为0（未使用交叉路径），指令的s位为1且x位为1（使用交叉路径），使src2寄存器指针指向regA寄存器
        src2LoRegPtr = read->getReg32ByName(RegAName[src2])->getDataPtr();
        if (src2 != static_cast<u32>(RegAKind::NUM_OF_Reg_A) - 1)
            src2HiRegPtr = read->getReg32ByName(RegAName[src2 + 1])->getDataPtr();
    } else {
        // 如果指令的s位为0且x位为1，指令的s位为1且x位为0，使src2寄存器指针指向regB寄存器
        src2LoRegPtr = read->getReg32ByName(RegBName[src2])->getDataPtr();
        if (src2 != static_cast<u32>(RegBKind::NUM_OF_Reg_B) - 1)
            src2HiRegPtr = read->getReg32ByName(RegBName[src2 + 1])->getDataPtr();
    }

    cRegPtr = write->getReg32ByName(CRegName[static_cast<u32>(getCRegKindByCrHiAndCrLo())])->getDataPtr();
    cstPtr = &this->cst;
    auxCstPtr = &this->auxCst;
}

std::string DspInstruction::getIRFuncName() const {
    return m_name + InstFormatStr[static_cast<u32>(instFormat)];
}

llvm::Value *DspInstruction::getDstLoRegPtr(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    return irBuilder->CreateLoad(llvmModule->getNamedGlobal("dstLoRegPtr"));
}

llvm::Value *DspInstruction::getDstHiRegPtr(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    return irBuilder->CreateLoad(llvmModule->getNamedGlobal("dstHiRegPtr"));
}

llvm::Value *DspInstruction::getSrc1LoRegPtr(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    return irBuilder->CreateLoad(llvmModule->getNamedGlobal("src1LoRegPtr"));
}

llvm::Value *DspInstruction::getSrc1HiRegPtr(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    return irBuilder->CreateLoad(llvmModule->getNamedGlobal("src1HiRegPtr"));
}

llvm::Value *DspInstruction::getSrc2LoRegPtr(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    return irBuilder->CreateLoad(llvmModule->getNamedGlobal("src2LoRegPtr"));
}

llvm::Value *DspInstruction::getSrc2HiRegPtr(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    return irBuilder->CreateLoad(llvmModule->getNamedGlobal("src2HiRegPtr"));
}

llvm::Value *DspInstruction::getCstN(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder, u32 N) {
    auto cstPtr = irBuilder->CreateLoad(llvmModule->getNamedGlobal("cstPtr"));
    auto cst = irBuilder->CreateLoad(cstPtr);
    return irBuilder->CreateTrunc(cst, irBuilder->getIntNTy(N));
}

llvm::Value *DspInstruction::getAuxCstN(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder, u32 N) {
    auto auxCstPtr = irBuilder->CreateLoad(llvmModule->getNamedGlobal("auxCstPtr"));
    auto auxCst = irBuilder->CreateLoad(auxCstPtr);
    return irBuilder->CreateTrunc(auxCst, irBuilder->getIntNTy(N));
}

llvm::Value *DspInstruction::getCRegPtr(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    return irBuilder->CreateLoad(llvmModule->getNamedGlobal("cRegPtr"));
}

bool DspInstruction::checkStandardCondition(std::shared_ptr<DspMachine> dspMachine) {
    auto regsMap = dspMachine->getSaveRegs();
    if (creg_z == 0b0000) {
        // Unconditional
        return true;
    } else if (creg_z == 0b0001 || creg_z == 0b1110 || creg_z == 0b1111) {
        return false;
    } else if (creg_z == 0b0010) {
        return *regsMap->getReg32ByName("B0")->getDataPtr() != 0;
    } else if (creg_z == 0b0011) {
        return *regsMap->getReg32ByName("B0")->getDataPtr() == 0;
    } else if (creg_z == 0b0100) {
        return *regsMap->getReg32ByName("B1")->getDataPtr() != 0;
    } else if (creg_z == 0b0101) {
        return *regsMap->getReg32ByName("B1")->getDataPtr() == 0;
    } else if (creg_z == 0b0110) {
        return *regsMap->getReg32ByName("B2")->getDataPtr() != 0;
    } else if (creg_z == 0b0111) {
        return *regsMap->getReg32ByName("B2")->getDataPtr() == 0;
    } else if (creg_z == 0b1000) {
        return *regsMap->getReg32ByName("A1")->getDataPtr() != 0;
    } else if (creg_z == 0b1001) {
        return *regsMap->getReg32ByName("A1")->getDataPtr() == 0;
    } else if (creg_z == 0b1010) {
        return *regsMap->getReg32ByName("A2")->getDataPtr() != 0;
    } else if (creg_z == 0b1011) {
        return *regsMap->getReg32ByName("A2")->getDataPtr() == 0;
    } else if (creg_z == 0b1100) {
        return *regsMap->getReg32ByName("A0")->getDataPtr() != 0;
    } else if (creg_z == 0b1101) {
        return *regsMap->getReg32ByName("A0")->getDataPtr() == 0;
    } else {
        return true;
    }
}

void
DspInstruction::fixUpAddressOffset(u32 &offset, AddressingMode addressingMode, std::shared_ptr<DspMachine> dspMachine) {
    if (addressingMode == AddressingMode::CircularBK0) {
        offset %= dspMachine->getAMRBlockSize(0);
    } else if (addressingMode == AddressingMode::CircularBK1) {
        offset %= dspMachine->getAMRBlockSize(1);
    }
}

u32 DspInstruction::computeRealAddress(const u32 *baseRReadPtr, u32 *baseRWritePtr, u32 addressingMethod, u32 leftshift,
                                       std::shared_ptr<DspMachine> dspMachine) {
    u32 realAddr = 0;               // 从内存中读取数据的真实地址
    u32 realOffset = 0;             // 该变量用于记录真实的offset（计算完循环寻址模式之后的访问地址偏移量）
    AddressingMode addressingMode;            // 基址寄存器的寻址模式

    if (addressingMethod == 0) {                      // *-R[ucst5]
        realOffset = cst << leftshift;
        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) - realOffset;
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) - realOffset;
        }
    } else if (addressingMethod == 1) {               // *+R[ucst5]
        realOffset = cst << leftshift;
        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) + realOffset;
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) + realOffset;
        }
    } else if (addressingMethod == 4) {               // *-R[offsetR]
        realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegAName[offsetR])->getDataPtr() << leftshift;
        if (y == 1)
            realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegBName[offsetR])->getDataPtr() << leftshift;

        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) - realOffset;
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) - realOffset;
        }
    } else if (addressingMethod == 5) {               // *+R[offsetR]
        realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegAName[offsetR])->getDataPtr() << leftshift;
        if (y == 1)
            realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegBName[offsetR])->getDataPtr() << leftshift;

        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) + realOffset;

        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr) + realOffset;
        }
    } else if (addressingMethod == 8) {               // *- -R[ucst5]
        realOffset = cst << leftshift;
        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr - realOffset;
            realAddr = (*baseRWritePtr);
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr - realOffset;
            realAddr = (*baseRWritePtr);
        }
    } else if (addressingMethod == 9) {               // *++R[ucst5]
        realOffset = cst << leftshift;
        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr + realOffset;
            realAddr = (*baseRWritePtr);
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr + realOffset;
            realAddr = (*baseRWritePtr);
        }
    } else if (addressingMethod == 10) {                  // *R- -[ucst5]
        realOffset = cst << leftshift;
        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr - realOffset;
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr - realOffset;
        }
    } else if (addressingMethod == 11) {                  // *R++[ucst5]
        realOffset = cst << leftshift;
        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr + realOffset;
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr + realOffset;
        }
    } else if (addressingMethod == 12) {                  // *--R[offsetR]
        realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegAName[offsetR])->getDataPtr() << leftshift;
        if (y == 1)
            realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegBName[offsetR])->getDataPtr() << leftshift;

        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr - realOffset;
            realAddr = (*baseRWritePtr);
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr - realOffset;
            realAddr = (*baseRWritePtr);
        }
    } else if (addressingMethod == 13) {                  // *++R[offsetR]
        realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegAName[offsetR])->getDataPtr() << leftshift;
        if (y == 1)
            realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegBName[offsetR])->getDataPtr() << leftshift;

        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr + realOffset;
            realAddr = (*baseRWritePtr);
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            *baseRWritePtr = *baseRReadPtr + realOffset;
            realAddr = (*baseRWritePtr);
        }
    } else if (addressingMethod == 14) {                  // *R- -[offsetR]
        realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegAName[offsetR])->getDataPtr() << leftshift;
        if (y == 1)
            realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegBName[offsetR])->getDataPtr() << leftshift;

        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr - realOffset;
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr - realOffset;
        }
    } else if (addressingMethod == 15) {                      // *R++[offsetR]
        realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegAName[offsetR])->getDataPtr() << leftshift;
        if (y == 1)
            realOffset = *dspMachine->getSaveRegs()->getReg32ByName(RegBName[offsetR])->getDataPtr() << leftshift;

        if (y == 0) {
            addressingMode = dspMachine->getRegAAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr + realOffset;
        } else {
            addressingMode = dspMachine->getRegBAddressingMode(baseR);
            fixUpAddressOffset(realOffset, addressingMode, dspMachine);
            realAddr = (*baseRReadPtr);
            *baseRWritePtr = *baseRReadPtr + realOffset;
        }
    }
    return realAddr;
}

void DspInstruction::fixUpRegOnCompactInstruction() {
    if (RS) {
        src1 += 16;
        src2 += 16;
        dst += 16;
    }
}

void DspInstruction::updateContextBeforeExecute(std::shared_ptr<TargetMachine> targetMachine,
                                                std::shared_ptr<LLVMJit> llvmJit) {
    std::shared_ptr<DspMachine> dspMachine = std::dynamic_pointer_cast<DspMachine>(targetMachine);
    // 指令执行之前，设置pce1寄存器，使pce1寄存器的值为当前执行的指令所在的取指包的第一条指令的地址
    auto pce1Reg = targetMachine->getRegisters()->getReg32ByName("PCE1");
    pce1Reg->updateData(getInstructionAddress() - getInstructionAddress() % 0x20);

    updateRegAndCstPtr(dspMachine->getSaveRegs(), dspMachine->getRegisters());
}

std::string DspInstruction::addressModeToString() const {
    std::string res;
    res = res + "*";
    switch (mode) {
        case 0:
            res += "-" + getBaseRRegName() + "[" + std::to_string(cst) + "]";
            break;
        case 1:
            res += "+" + getBaseRRegName() + "[" + std::to_string(cst) + "]";
            break;
        case 4:
            res += "-" + getBaseRRegName() + "[" + getOffsetRRegName() + "]";
            break;
        case 5:
            res += "+" + getBaseRRegName() + "[" + getOffsetRRegName() + "]";
            break;
        case 8:
            res += "--" + getBaseRRegName() + "[" + std::to_string(cst) + "]";
            break;
        case 9:
            res += "++" + getBaseRRegName() + "[" + std::to_string(cst) + "]";
            break;
        case 10:
            res += getBaseRRegName() + "--" + "[" + std::to_string(cst) + "]";
            break;
        case 11:
            res += getBaseRRegName() + "++" + "[" + std::to_string(cst) + "]";
            break;
        case 12:
            res += "--" + getBaseRRegName() + "[" + getOffsetRRegName() + "]";
            break;
        case 13:
            res += "++" + getBaseRRegName() + "[" + getOffsetRRegName() + "]";
            break;
        case 14:
            res += getBaseRRegName() + "--" + "[" + getOffsetRRegName() + "]";
            break;
        case 15:
            res += getBaseRRegName() + "++" + "[" + getOffsetRRegName() + "]";
            break;
        default:
            break;
    }
    return res;
}

void DspInstruction::storeLongIntoDst(std::shared_ptr<llvm::IRBuilder<>> &irBuilder, llvm::Value *longSrc,
                                      llvm::Value *dstLoPtr, llvm::Value *dstHiPtr) {

    auto longLo32 = irBuilder->CreateTrunc(longSrc, irBuilder->getInt32Ty());
    irBuilder->CreateStore(longLo32, dstLoPtr);
    auto temp1 = irBuilder->CreateLShr(longSrc, 32);
    auto temp2 = irBuilder->CreateTrunc(temp1, irBuilder->getInt32Ty());
    auto dstHi = irBuilder->CreateLoad(dstHiPtr);
    auto temp3 = irBuilder->CreateAnd(dstHi, irBuilder->getInt32(0xffffff00));
    auto longHi32 = irBuilder->CreateOr(temp3, temp2);
    irBuilder->CreateStore(longHi32, dstHiPtr);
}

llvm::Value *DspInstruction::loadLongSrc2ByIR(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    auto src2Lo = irBuilder->CreateLoad(getSrc2LoRegPtr(llvmModule, irBuilder));
    auto src2Hi = irBuilder->CreateLoad(getSrc2HiRegPtr(llvmModule, irBuilder));
    auto srcLongLo = irBuilder->CreateZExt(src2Lo, irBuilder->getIntNTy(40));
    auto temp1 = irBuilder->CreateZExt(src2Hi, irBuilder->getIntNTy(40));
    auto srcLongHi = irBuilder->CreateShl(temp1, irBuilder->getIntN(40, 32));
    auto res = irBuilder->CreateOr(srcLongHi, srcLongLo);
    return res;

}

llvm::Value *DspInstruction::loadLongSrc1ByIR(llvm::Module *llvmModule, std::shared_ptr<llvm::IRBuilder<>> irBuilder) {
    auto src1Lo = irBuilder->CreateLoad(getSrc1LoRegPtr(llvmModule, irBuilder));
    auto src1Hi = irBuilder->CreateLoad(getSrc1HiRegPtr(llvmModule, irBuilder));
    auto srcLongLo = irBuilder->CreateZExt(src1Lo, irBuilder->getIntNTy(40));
    auto temp1 = irBuilder->CreateZExt(src1Hi, irBuilder->getIntNTy(40));
    auto srcLongHi = irBuilder->CreateShl(temp1, irBuilder->getIntN(40, 32));
    auto res = irBuilder->CreateOr(srcLongHi, srcLongLo);
    return res;
}
